#include "CurveFitting.hpp"
#include <vector>
#include <cmath>
#include <iostream>
#include <fstream>
#include <utility>

const double PI = acos(-1.); // Define PI

// Define the R1 curve functions
class R1X : public Function {
public:
    double operator()(double t) const override {
        return sqrt(3) * cos(t); // x-coordinate
    }
};

class R1Y : public Function {
public:
    double operator()(double t) const override {
        double x = sqrt(3) * cos(t);
        return (2.0 / 3.0) * sqrt(fabs(x)) + (2.0 / 3.0) * sqrt(3) * sin(t); // y-coordinate
    }
};

// Define the R2 curve functions
class R2X : public Function {
public:
    double operator()(double t) const override {
        return sin(t) + t * cos(t);
    }
};

class R2Y : public Function {
public:
    double operator()(double t) const override {
        return cos(t) - t * sin(t);
    }
};

// Define the R3 curve functions
class R3X : public Function {
public:
    double operator()(double t) const override {
        return cos(3 * t);
    }
};

class R3Y : public Function {
public:
    double operator()(double t) const override {
        return sin(4 * t);
    }
};

// Define the R4 curve functions
class R4X : public Function {
public:
    double operator()(double t) const override {
        return cos(t);
    }
};

class R4Y : public Function {
public:
    double operator()(double t) const override {
        return sin(2 * t);
    }
};

int main() {
    R1X r1xFunc;
    R1Y r1yFunc;
    PlaneCurve r1Curve(&r1xFunc, &r1yFunc, 0, 2 * PI);

    R2X r2xFunc;
    R2Y r2yFunc;
    PlaneCurve r2Curve(&r2xFunc, &r2yFunc, 0, 6 * PI);

    R3X r3xFunc;
    R3Y r3yFunc;
    PlaneCurve r3Curve(&r3xFunc, &r3yFunc, 0, 2 * PI);

    R4X r4xFunc;
    R4Y r4yFunc;
    PlaneCurve r4Curve(&r4xFunc, &r4yFunc, 0, 2 * PI);

    int m = 100; // Number of segments for testing

    bool r1SelfIntersecting = r1Curve.isSelfIntersecting(m);
    bool r2SelfIntersecting = r2Curve.isSelfIntersecting(m);
    bool r3SelfIntersecting = r3Curve.isSelfIntersecting(m);
    bool r4SelfIntersecting = r4Curve.isSelfIntersecting(m);

    std::cout << "R1 curve is " << (r1SelfIntersecting ? "self-intersecting" : "not self-intersecting") << std::endl;
    std::cout << "R2 curve is " << (r2SelfIntersecting ? "self-intersecting" : "not self-intersecting") << std::endl;
    std::cout << "R3 curve is " << (r3SelfIntersecting ? "self-intersecting" : "not self-intersecting") << std::endl;
    std::cout << "R4 curve is " << (r4SelfIntersecting ? "self-intersecting" : "not self-intersecting") << std::endl;

    return 0;
}
